package grails.company

import grails.converters.JSON
import grails.test.mixin.*
import grails.test.mixin.domain.DomainClassUnitTestMixin
import org.junit.Before

import static org.junit.Assert.assertThat
import static org.junit.matchers.JUnitMatchers.*

/**
 * See the API for {@link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
 */
@TestFor(EmployeeController)
@Mock([Organization, Department, Project, Employee])
class EmployeeControllerTests {

    Project p
    Employee e

    @Before
    void setUp() {
        def o = new Organization(title: 'ACME', description: 'desc').save()
        def d = new Department(title: 'Cartoons', description: 'desc', organization: o).save()
        p = new Project(title: 'Toy story', description: 'desc', department: d).save()
        e = new Employee(firstName: 'George', lastName: 'Bush', emailAddress: 'george@ACME.com', accountName: 'gbush', project: p).save()
        new Employee(firstName: 'Kevin', lastName: 'Spacey', emailAddress: 'kevin@ACME.com', accountName: 'kspacey', project: p).save()
        params.data = [:]
    }

    private void assertResponseSuccess(boolean success = true) {
        def json = JSON.parse(response.contentAsString)
        assertNotNull json
        assertEquals(json.success, success)
    }

    private void assertEmployee(def json, Employee emp) {
        assertNotNull emp
        assertNotNull emp.project
        assertEquals(json.firstName, emp.firstName)
        assertEquals(json.lastName, emp.lastName)
        assertEquals(json.emailAddress, emp.emailAddress)
        assertEquals(json.accountName, emp.accountName)
        assertEquals(json.parentId, emp.project.id)
    }

    private void mockParams(def params, Employee e = null) {
        params.data.id = e?.id
        params.data.firstName = e?.firstName ?: 'firstName'
        params.data.lastName = e?.lastName ?: 'lastName'
        params.data.emailAddress = e?.emailAddress ?: 'email@Address.com'
        params.data.accountName = e?.accountName ?: 'accname'
        params.data.parentId = e?.project?.id ?: p.id
    }

    void testListEmpty() {
        Employee.metaClass.static.list = {-> [] }

        controller.list()

        assertResponseSuccess(false)
    }

    void testListNonEmpty() {
        controller.list()

        assertResponseSuccess()
        def json = JSON.parse(response.contentAsString)
        assertEmployee(json.data[0], e)
    }

    void testViewNoIdSet() {
        controller.view()

        assertResponseSuccess()
        def json = JSON.parse(response.contentAsString)
        assertEmployee(json.data[0], e)
    }

    void testViewInvalidIdSet() {
        params.data.id = -1

        controller.view()

        assertResponseSuccess(false)
    }

    void testViewValidIdSet() {
        params.data.id = e.id

        controller.view()

        assertResponseSuccess()
        def json = JSON.parse(response.contentAsString)
        assertEmployee(json.data, e)
    }

    void testUpdateNoIdSet() {
        controller.update()

        assertResponseSuccess(false)
    }

    void testUpdateNoTitleSet() {
        params.data.id = e.id

        controller.update()

        assertResponseSuccess(false)
    }

    void testUpdateInvalidIdSet() {
        params.data.id = -1

        controller.update()

        assertResponseSuccess(false)
    }

    void testUpdateValidate() {
        Employee.metaClass.validate = {-> false }
        mockParams(params, e)

        controller.update()

        assertResponseSuccess(false)
    }

    void testUpdateValidSet() {
        mockParams(params, e)
        params.data.firstName = 'NewFirstName'

        controller.update()

        assertResponseSuccess()
        assertNotNull Employee.findByFirstName('NewFirstName')
    }

    void testDeleteNoIdSet() {
        controller.delete()

        assertResponseSuccess(false)
    }

    void testDeleteInvalidIdSet() {
        params.data.id = -1

        controller.delete()

        assertResponseSuccess(false)
    }

    void testDeleteValidIdSet() {
        params.data.id = Employee.findByAccountName('gbush').id

        controller.delete()

        assertResponseSuccess()
        assertNull Employee.findByAccountName('gbush')
    }

    void testCreateNoParentIdSet() {
        controller.create()

        assertResponseSuccess(false)
    }

    void testCreateInvalidParentIdSet() {
        mockParams(params)
        params.data.parentId = -1

        controller.create()

        assertResponseSuccess(false)
    }

    void testCreateValidate() {
        Employee.metaClass.validate = {-> false }
        mockParams(params)

        controller.create()

        assertResponseSuccess(false)
    }

    void testCreateSave() {
        Employee.metaClass.save = {-> false }
        mockParams(params)

        controller.create()

        assertResponseSuccess(false)
    }

    void testCreateValid() {
        mockParams(params)

        controller.create()

        assertResponseSuccess()
        def emp = Employee.findByAccountName(params.data.accountName)
        def json = JSON.parse(response.contentAsString)
        assertEmployee(json.data, emp)
        assertEquals(json.data.id, emp.id)
        assertTrue p.employees.contains(emp)
    }
}
